package org.citra.citra_emu.activities;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
import android.text.TextUtils;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationManagerCompat;

import com.aiwu.ArchiveBackupManger;
import com.aiwu.ArchiveManger;
import com.aiwu.InputManager;
import com.aiwu.NetPlayManager;
import com.aiwu.PrefsHelper;
import com.aiwu.ScreenEditActivity;
import com.aiwu.Util;
import com.aiwu.interfaces.ScreenLayoutListener;
import com.aiwu.library.AiwuSimulator;
import com.aiwu.library.OperateManager;
import com.aiwu.library.bean.ClickOperateButtonBean;
import com.aiwu.library.bean.Direction;
import com.aiwu.library.bean.OneKeyOperate;
import com.aiwu.library.bean.RockerOperateButtonBean;
import com.aiwu.library.interfaces.OperateListener;
import com.aiwu.library.interfaces.SimulatorCallback;
import com.aiwu.library.netWork.MyOkGo;
import com.aiwu.library.ui.pop.TipPop;
import com.aiwu.library.ui.view.BaseOperateRocker;
import com.aiwu.library.util.DialogUtil;
import com.aiwu.library.util.IOUtil;
import com.aiwu.library.util.LogUtil;
import com.aiwu.library.util.ToastUtil;
import com.aiwu.memory.MemoryDialogActivity;
import com.aiwu.pop.FastSettingDialog;
import com.aiwu.widget.FloatingLayout;

import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.R;
import org.citra.citra_emu.camera.StillImageCameraHelper;
import org.citra.citra_emu.features.settings.model.IntSetting;
import org.citra.citra_emu.features.settings.model.Setting;
import org.citra.citra_emu.features.settings.model.SettingSection;
import org.citra.citra_emu.features.settings.model.Settings;
import org.citra.citra_emu.features.settings.model.StringSetting;
import org.citra.citra_emu.features.settings.ui.SettingsActivity;
import org.citra.citra_emu.features.settings.utils.SettingsFile;
import org.citra.citra_emu.fragments.EmulationFragment;
import org.citra.citra_emu.ui.main.MainActivity;
import org.citra.citra_emu.utils.EmulationMenuSettings;
import org.citra.citra_emu.utils.FileBrowserHelper;
import org.citra.citra_emu.utils.FileUtil;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import rx.Completable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.RECORD_AUDIO;
import static java.lang.annotation.RetentionPolicy.SOURCE;

public final class EmulationActivity extends AppCompatActivity implements ArchiveManger.OnArchiveCallback {
    private final static String TAG = EmulationActivity.class.getName();

    public static final String EXTRA_SELECTED_GAME = "SelectedGame";
    public static final String EXTRA_MARKET_GAME = "MarketTitle";
    public static final String EXTRA_SELECTED_TITLE = "SelectedTitle";
    public static final int MENU_ACTION_EDIT_CONTROLS_PLACEMENT = 0;
    public static final int MENU_ACTION_TOGGLE_CONTROLS = 1;
    public static final int MENU_ACTION_ADJUST_SCALE = 2;
    public static final int MENU_ACTION_EXIT = 3;
    public static final int MENU_ACTION_SHOW_FPS = 4;
    public static final int MENU_ACTION_SCREEN_LAYOUT_LANDSCAPE = 5;
    public static final int MENU_ACTION_SCREEN_LAYOUT_PORTRAIT = 6;
    public static final int MENU_ACTION_SCREEN_LAYOUT_SINGLE = 7;
    public static final int MENU_ACTION_SCREEN_LAYOUT_SIDEBYSIDE = 8;
    public static final int MENU_ACTION_SWAP_SCREENS = 9;
    public static final int MENU_ACTION_RESET_OVERLAY = 10;
    public static final int MENU_ACTION_SHOW_OVERLAY = 11;
    public static final int MENU_ACTION_OPEN_SETTINGS = 12;
    public static final int MENU_ACTION_LOAD_AMIIBO = 13;
    public static final int MENU_ACTION_REMOVE_AMIIBO = 14;
    public static final int MENU_ACTION_JOYSTICK_REL_CENTER = 15;

    public static final int REQUEST_SELECT_AMIIBO = 2;
    public static final int REQUEST_SELECT_DLC_OR_PATCH = 3;
    private static final int EMULATION_RUNNING_NOTIFICATION = 0x1000;
    private static SparseIntArray buttonsActionsMap = new SparseIntArray();

    static {
        buttonsActionsMap.append(R.id.menu_emulation_edit_layout,
                EmulationActivity.MENU_ACTION_EDIT_CONTROLS_PLACEMENT);
        buttonsActionsMap.append(R.id.menu_emulation_toggle_controls,
                EmulationActivity.MENU_ACTION_TOGGLE_CONTROLS);
        buttonsActionsMap
                .append(R.id.menu_emulation_adjust_scale, EmulationActivity.MENU_ACTION_ADJUST_SCALE);
        buttonsActionsMap.append(R.id.menu_emulation_show_fps,
                EmulationActivity.MENU_ACTION_SHOW_FPS);
        buttonsActionsMap.append(R.id.menu_screen_layout_landscape,
                EmulationActivity.MENU_ACTION_SCREEN_LAYOUT_LANDSCAPE);
        buttonsActionsMap.append(R.id.menu_screen_layout_portrait,
                EmulationActivity.MENU_ACTION_SCREEN_LAYOUT_PORTRAIT);
        buttonsActionsMap.append(R.id.menu_screen_layout_single,
                EmulationActivity.MENU_ACTION_SCREEN_LAYOUT_SINGLE);
        buttonsActionsMap.append(R.id.menu_screen_layout_sidebyside,
                EmulationActivity.MENU_ACTION_SCREEN_LAYOUT_SIDEBYSIDE);
        buttonsActionsMap.append(R.id.menu_emulation_swap_screens,
                EmulationActivity.MENU_ACTION_SWAP_SCREENS);
        buttonsActionsMap
                .append(R.id.menu_emulation_reset_overlay, EmulationActivity.MENU_ACTION_RESET_OVERLAY);
        buttonsActionsMap
                .append(R.id.menu_emulation_show_overlay, EmulationActivity.MENU_ACTION_SHOW_OVERLAY);
        buttonsActionsMap
                .append(R.id.menu_emulation_open_settings, EmulationActivity.MENU_ACTION_OPEN_SETTINGS);
        buttonsActionsMap
                .append(R.id.menu_emulation_amiibo_load, EmulationActivity.MENU_ACTION_LOAD_AMIIBO);
        buttonsActionsMap
                .append(R.id.menu_emulation_amiibo_remove, EmulationActivity.MENU_ACTION_REMOVE_AMIIBO);
        buttonsActionsMap.append(R.id.menu_emulation_joystick_rel_center,
                EmulationActivity.MENU_ACTION_JOYSTICK_REL_CENTER);
    }

    private View mDecorView;
    private EmulationFragment mEmulationFragment;
    //    private Intent foregroundService;
    private boolean activityRecreated;
    private String mSelectedTitle;
    private String mPath;
    //盒子传过来的路径
    private String mMarketRomPath;

    private FloatingLayout mFloatingLayout;
    private FrameLayout mFrameContent;
    private ScreenLayoutListener mScreenLayoutListener;
    private InputManager inputManager;

    public static void launch(Activity activity, String path, String title) {
        launch(activity, path, title, "");
    }

    public static void launch(Activity activity, String path, String title, String marketRomPath) {
        Intent launcher = new Intent(activity, EmulationActivity.class);

        launcher.putExtra(EXTRA_SELECTED_GAME, path);
        launcher.putExtra(EXTRA_MARKET_GAME, marketRomPath);
        launcher.putExtra(EXTRA_SELECTED_TITLE, title);
        activity.startActivity(launcher);
    }

    public static void tryDismissRunningNotification(Activity activity) {
        NotificationManagerCompat.from(activity).cancel(EMULATION_RUNNING_NOTIFICATION);
    }

    @Override
    protected void onDestroy() {
//        stopService(foregroundService);
        ArchiveBackupManger.getInstance().stopTimer();
        super.onDestroy();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {
            // Get params we were passed
            Intent gameToEmulate = getIntent();
            mPath = gameToEmulate.getStringExtra(EXTRA_SELECTED_GAME);
            mMarketRomPath = gameToEmulate.getStringExtra(EXTRA_MARKET_GAME);
            mSelectedTitle = gameToEmulate.getStringExtra(EXTRA_SELECTED_TITLE);
            activityRecreated = false;
        } else {
            activityRecreated = true;
            restoreState(savedInstanceState);
        }

        // Get a handle to the Window containing the UI.
        mDecorView = getWindow().getDecorView();
        mDecorView.setOnSystemUiVisibilityChangeListener(visibility ->
        {
            if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                // Go back to immersive fullscreen mode in 3s
                Handler handler = new Handler(getMainLooper());
                handler.postDelayed(this::enableFullscreenImmersive, 3000 /* 3s */);
            }
        });
        // Set these options now so that the SurfaceView the game renders into is the right size.
        enableFullscreenImmersive();

        // Start a foreground service to prevent the app from getting killed in the background
//        foregroundService = new Intent(EmulationActivity.this, ForegroundService.class);
//        startForegroundService(foregroundService);

//        setTheme(R.style.CitraEmulationBase);

        setContentView(R.layout.activity_emulation);
        mFrameContent = findViewById(R.id.frame_content);

        // Find or create the EmulationFragment
        mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
                .findFragmentById(R.id.frame_emulation_fragment);
        if (mEmulationFragment == null) {
            mEmulationFragment = EmulationFragment.newInstance(mPath);
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.frame_emulation_fragment, mEmulationFragment)
                    .commit();
        }

        //setTitle(mSelectedTitle);
        // Override Citra core INI with the one set by our in game menu
        NativeLibrary.SwapScreens(EmulationMenuSettings.getSwapScreens(),
                getWindowManager().getDefaultDisplay().getRotation());

        //region 修改
        //更新信息提示
        mFloatingLayout = findViewById(R.id.floating_layout);
        showUpdateInfoIfNecessary();
        initCallbackAndListener();
        //endregion
    }

    private void showUpdateInfoIfNecessary() {
        int currentVersionCode = MyOkGo.getVersionCode(this);
        boolean isNewVersion = PrefsHelper.getInstance().isNewVersion(currentVersionCode);
        if (isNewVersion) {
            DialogUtil.showTip(this, "1.10.4版更新说明",
                    "1.优化 屏幕按键透明度"
                    , "确定", null, null, null);
        }
    }

    private void initCallbackAndListener() {
        inputManager = new InputManager();
        initAiwuParams();
        AiwuSimulator.addStatusChangeCallback((newStatus, oldStatus) -> {
            if (mFloatingLayout != null)
                mFloatingLayout.setVisibility((newStatus == OperateManager.EDIT || newStatus == OperateManager.PAUSE) ? View.GONE : View.VISIBLE);
        });
        ArchiveBackupManger.getInstance().setArchiveListener(mMarketRomPath, this::reloadGame);
        ArchiveManger.getInstance().init(this);

        AiwuSimulator.setCallback(new SimulatorCallback() {
            @Override
            public void pause() {
                NativeLibrary.PauseEmulation();
            }

            @Override
            public void resume() {
                NativeLibrary.UnPauseEmulation();
            }

            @Override
            public void onMenuClick(View view, com.aiwu.library.bean.Menu menu, Object param) {
                switch (menu) {
                    case BOTTOM_RELOAD:
                        showReloadConfirmation();
                        break;
                    case FAST_SETTING://快速设置
                        AlertDialog dialog = new FastSettingDialog(EmulationActivity.this, CitraApplication.getRomName());
                        dialog.show();
                        DialogUtil.setDialog(dialog, 0.6f, 0.9f, 0.8f, 0.6f);
                        break;
                    case BOTTOM_SETTING:
                        SettingsActivity.launch(EmulationActivity.this, SettingsFile.FILE_NAME_CONFIG, "");
                        break;
                    case BOTTOM_EXIT:
                        showExitConfirmation();
                        break;
                    case BOTTOM_SOUND:
                        setSoundEnable((boolean) param);
                        break;
                    case FAST_ORIENTATION:
                        resetScreenLayout();
                        PrefsHelper.getInstance().removeFloatingBottomScreenLocation();
                        PrefsHelper.getInstance().resetFloatingScreenLayout();
                        break;
                    case FAST_MEMORY:
                        MemoryDialogActivity.launch(EmulationActivity.this);
                        break;
                    case FAST_SPEED:
                        setSpeedUp((int) param);
                        break;
                    case FAST_SNAP:
                        snap();
                        break;
                    case BOTTOM_FIGHT:
                        NetPlayManager.showNetPlayDialog(EmulationActivity.this);
                        break;
                    default:
                        break;
                }
            }

            @Override
            public void setActOrientation(int orientation) {
                setRequestedOrientation(orientation);
            }
        }, new OperateListener() {
            @Override
            public void onButtonClick(View view, int player, boolean burst, ClickOperateButtonBean... buttons) {
                inputManager.onButtonClick(burst, buttons);
            }

            @Override
            public void onButtonRelease(View view, int player, boolean burst, ClickOperateButtonBean... buttons) {
                inputManager.onButtonRelease(burst, buttons);
            }

            @Override
            public void onOneKeyClick(View view, int player, boolean advancedMode, List<OneKeyOperate> buttons) {
                inputManager.onOneKeyClick(advancedMode, buttons);
            }

            @Override
            public void onTouchEvent(MotionEvent event) {
                inputManager.onTouchEvent(event);
            }
        }, BaseOperateRocker.DirectionMode.DIRECTION_8, BaseOperateRocker.CallBackMode.CALL_BACK_MODE_MOVE, new BaseOperateRocker.OnShakeListener() {
            @Override
            public void onStart(RockerOperateButtonBean rocker) {

            }

            @Override
            public void direction(Direction direction, RockerOperateButtonBean rocker) {
                if (rocker.getId().equals(InputManager.KEY_ROCKER_CROSS)) {
                    inputManager.onDirectionChanged(direction);
                }
            }

            @Override
            public void onFinish(Direction lastDirection, RockerOperateButtonBean rocker) {
                if (rocker.getId().equals(InputManager.KEY_ROCKER_CROSS)) {
                    inputManager.resetDirection();
                }
            }
        }, new BaseOperateRocker.OnAxisesChangeListener() {
            @Override
            public void onStart(RockerOperateButtonBean rocker) {

            }

            @Override
            public void axises(float xAxisesRatio, float yAxisesRatio, RockerOperateButtonBean rocker) {
                if (rocker.getId().equals(InputManager.KEY_ROCKER_MAIN)) {
                    inputManager.onAxisesChanged(xAxisesRatio, yAxisesRatio, true);
                } else if (rocker.getId().equals(InputManager.KEY_ROCKER_C)) {
                    inputManager.onAxisesChanged(xAxisesRatio, yAxisesRatio, false);
                }
            }

            @Override
            public void onFinish(RockerOperateButtonBean rocker) {
                if (rocker.getId().equals(InputManager.KEY_ROCKER_MAIN)) {
                    inputManager.resetAxises(true);
                } else if (rocker.getId().equals(InputManager.KEY_ROCKER_C)) {
                    inputManager.resetAxises(false);
                }
            }
        });
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        outState.putString(EXTRA_SELECTED_GAME, mPath);
        outState.putString(EXTRA_MARKET_GAME, mMarketRomPath);
        outState.putString(EXTRA_SELECTED_TITLE, mSelectedTitle);
        super.onSaveInstanceState(outState);
    }

    protected void restoreState(Bundle savedInstanceState) {
        mPath = savedInstanceState.getString(EXTRA_SELECTED_GAME);
        mMarketRomPath = savedInstanceState.getString(EXTRA_MARKET_GAME);
        mSelectedTitle = savedInstanceState.getString(EXTRA_SELECTED_TITLE);

        // If an alert prompt was in progress when state was restored, retry displaying it
        NativeLibrary.retryDisplayAlertPrompt();
    }

    @Override
    public void onRestart() {
        super.onRestart();
        NativeLibrary.ReloadCameraDevices();
    }

    @Override
    public void onBackPressed() {
        if (!AiwuSimulator.onBackPressed()) {
            showExitConfirmation();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case NativeLibrary.REQUEST_CODE_NATIVE_CAMERA:
                if (grantResults[0] != PackageManager.PERMISSION_GRANTED &&
                        shouldShowRequestPermissionRationale(CAMERA)) {
                    new AlertDialog.Builder(this)
                            .setTitle(R.string.camera)
                            .setMessage(R.string.camera_permission_needed)
                            .setPositiveButton(android.R.string.ok, null)
                            .show();
                }
                NativeLibrary.CameraPermissionResult(grantResults[0] == PackageManager.PERMISSION_GRANTED);
                break;
            case NativeLibrary.REQUEST_CODE_NATIVE_MIC:
                if (grantResults[0] != PackageManager.PERMISSION_GRANTED &&
                        shouldShowRequestPermissionRationale(RECORD_AUDIO)) {
                    new AlertDialog.Builder(this)
                            .setTitle(R.string.microphone)
                            .setMessage(R.string.microphone_permission_needed)
                            .setPositiveButton(android.R.string.ok, null)
                            .show();
                }
                NativeLibrary.MicPermissionResult(grantResults[0] == PackageManager.PERMISSION_GRANTED);
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
                break;
        }
    }

    private void enableFullscreenImmersive() {
        // It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar.
        if (mDecorView != null) {
            mDecorView.setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                            View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
                            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
                            View.SYSTEM_UI_FLAG_FULLSCREEN |
                            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        }
    }

//    @Override
//    public boolean onCreateOptionsMenu(Menu menu) {
//        // Inflate the menu; this adds items to the action bar if it is present.
//        getMenuInflater().inflate(R.menu.menu_emulation, menu);
//
//        int layoutOptionMenuItem = R.id.menu_screen_layout_landscape;
//        switch (EmulationMenuSettings.getLandscapeScreenLayout()) {
//            case EmulationMenuSettings.LayoutOption_SingleScreen:
//                layoutOptionMenuItem = R.id.menu_screen_layout_single;
//                break;
//            case EmulationMenuSettings.LayoutOption_SideScreen:
//                layoutOptionMenuItem = R.id.menu_screen_layout_sidebyside;
//                break;
//            case EmulationMenuSettings.LayoutOption_MobilePortrait:
//                layoutOptionMenuItem = R.id.menu_screen_layout_portrait;
//                break;
//        }
//
//        menu.findItem(layoutOptionMenuItem).setChecked(true);
//        menu.findItem(R.id.menu_emulation_joystick_rel_center).setChecked(EmulationMenuSettings.getJoystickRelCenter());
//        menu.findItem(R.id.menu_emulation_show_fps).setChecked(EmulationMenuSettings.getShowFps());
//        menu.findItem(R.id.menu_emulation_swap_screens).setChecked(EmulationMenuSettings.getSwapScreens());
//        menu.findItem(R.id.menu_emulation_show_overlay).setChecked(EmulationMenuSettings.getShowOverlay());
//
//        return true;
//    }

    @SuppressWarnings("WrongConstant")
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int action = buttonsActionsMap.get(item.getItemId(), -1);

        switch (action) {
            // Edit the placement of the controls
            case MENU_ACTION_EDIT_CONTROLS_PLACEMENT:
                break;

            // Enable/Disable specific buttons or the entire input overlay.
            case MENU_ACTION_TOGGLE_CONTROLS:
                break;

            // Adjust the scale of the overlay controls.
            case MENU_ACTION_ADJUST_SCALE:
                break;

            // Toggle the visibility of the Performance stats TextView
            case MENU_ACTION_SHOW_FPS: {
                final boolean isEnabled = !EmulationMenuSettings.getShowFps();
                EmulationMenuSettings.setShowFps(isEnabled);
                item.setChecked(isEnabled);

                mEmulationFragment.updateShowFpsOverlay();
                break;
            }
            // Sets the screen layout to Landscape
            case MENU_ACTION_SCREEN_LAYOUT_LANDSCAPE:
                changeScreenOrientation(EmulationMenuSettings.LayoutOption_MobileLandscape, item);
                break;

            // Sets the screen layout to Portrait
            case MENU_ACTION_SCREEN_LAYOUT_PORTRAIT:
                changeScreenOrientation(EmulationMenuSettings.LayoutOption_MobilePortrait, item);
                break;

            // Sets the screen layout to Single
            case MENU_ACTION_SCREEN_LAYOUT_SINGLE:
                changeScreenOrientation(EmulationMenuSettings.LayoutOption_SingleScreen, item);
                break;

            // Sets the screen layout to Side by Side
            case MENU_ACTION_SCREEN_LAYOUT_SIDEBYSIDE:
                changeScreenOrientation(EmulationMenuSettings.LayoutOption_SideScreen, item);
                break;

            // Swap the top and bottom screen locations
            case MENU_ACTION_SWAP_SCREENS: {
                final boolean isEnabled = !EmulationMenuSettings.getSwapScreens();
                EmulationMenuSettings.setSwapScreens(isEnabled);
                item.setChecked(isEnabled);

                NativeLibrary.SwapScreens(isEnabled, getWindowManager().getDefaultDisplay()
                        .getRotation());
                break;
            }

            // Reset overlay placement
            case MENU_ACTION_RESET_OVERLAY:
                break;

            // Show or hide overlay
            case MENU_ACTION_SHOW_OVERLAY:
                break;

            case MENU_ACTION_EXIT:
                mEmulationFragment.stopEmulation();
                finish();
                break;

            case MENU_ACTION_OPEN_SETTINGS:
                SettingsActivity.launch(this, SettingsFile.FILE_NAME_CONFIG, "");
                break;

            case MENU_ACTION_LOAD_AMIIBO:
                ChooseAmiibo();
                break;

            case MENU_ACTION_REMOVE_AMIIBO:
                RemoveAmiibo();
                break;

            case MENU_ACTION_JOYSTICK_REL_CENTER:
                final boolean isEnabled = !EmulationMenuSettings.getJoystickRelCenter();
                EmulationMenuSettings.setJoystickRelCenter(isEnabled);
                item.setChecked(isEnabled);
                break;
        }

        return true;
    }

    private void changeScreenOrientation(int layoutOption, MenuItem item) {
        if (item != null)
            item.setChecked(true);
        NativeLibrary.NotifyOrientationChange(layoutOption, getWindowManager().getDefaultDisplay()
                .getRotation());
        EmulationMenuSettings.setLandscapeScreenLayout(layoutOption);
    }


    // Gets button presses
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (inputManager.dispatchKeyEvent(event)) {
            return true;
        }
        return super.dispatchKeyEvent(event);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent result) {
        super.onActivityResult(requestCode, resultCode, result);
        switch (requestCode) {
            case StillImageCameraHelper.REQUEST_CAMERA_FILE_PICKER:
                StillImageCameraHelper.OnFilePickerResult(resultCode == RESULT_OK ? result : null);
                break;
            case REQUEST_SELECT_AMIIBO:
                // If the user picked a file, as opposed to just backing out.
                if (resultCode == MainActivity.RESULT_OK) {
                    String[] selectedFiles = FileBrowserHelper.getSelectedFiles(result);
                    if (selectedFiles == null)
                        return;

                    onAmiiboSelected(selectedFiles[0]);
                }
                break;
            case REQUEST_SELECT_DLC_OR_PATCH:
                // If the user picked a file, as opposed to just backing out.
                if (resultCode == MainActivity.RESULT_OK) {
                    String[] selectedFiles = FileBrowserHelper.getSelectedFiles(result);
                    if (selectedFiles == null)
                        return;

                    onSelectDLCOrPatchFile(selectedFiles[0]);
                }
                break;
            //region 修改
            case ScreenEditActivity.REQUEST_CODE:
                if (resultCode == RESULT_OK) {
                    if (mScreenLayoutListener != null) {
                        int action = result.getIntExtra(ScreenEditActivity.RESULT_ACTION, ScreenEditActivity.RESULT_INSERTED);
                        int layoutId = result.getIntExtra(ScreenEditActivity.RESULT_ID, -1);
                        if (layoutId == -1) {
                            return;
                        }
                        if (action == ScreenEditActivity.RESULT_INSERTED) {
                            mScreenLayoutListener.layoutInserted(layoutId);
                        } else {
                            mScreenLayoutListener.layoutEdited(layoutId);
                        }
                    }
                }
                break;
            default:
                break;
            //endregion
        }
    }

    private void onSelectDLCOrPatchFile(String filePath) {
        if (filePath.endsWith("zip")) {
            if (Util.isSameGameIdFromZip(filePath, Util.getLast8Id(CitraApplication.getRomName()))) {
                Completable.fromAction(() -> {
                    Util.moveDLCOrPatchFileFromUnZipTemporaryFile(Util.getLast8Id(CitraApplication.getRomName()));
                    Util.deleteUnZipTemporaryFile();
                }).subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .doOnSubscribe(subscription -> {
                            showLoadingDialog("安装中", "安装中,请耐心等待…", false);
                        })
                        .doOnCompleted(this::dismissLoadingDialog)
                        .subscribe(() -> {
                            ToastUtil.toast("安装完成,重新启动游戏");
                            reloadGame();
                        }, throwable -> {
                            ToastUtil.toast("错误：安装DLC或补丁失败");
                            LogUtil.d(TAG, throwable.getMessage());
                        });

            } else {
                Util.deleteUnZipTemporaryFile();
                ToastUtil.toast("该ZIP文件不是该游戏的DLC或补丁,请重新选择");
            }
        }
        if (filePath.endsWith("cia")) {
            try {
                String gameId = Util.getIdFromGameFile(new BufferedInputStream(new FileInputStream(filePath)));
                if (!Util.getLast8Id(CitraApplication.getRomName()).equals(Util.getLast8Id(gameId))) {
                    ToastUtil.toast("该CIA文件不是该游戏的DLC或补丁,请重新选择");
                    return;
                }
                Completable.fromAction(() -> {
                    NativeLibrary.InstallCIAS(new String[]{filePath});
                }).subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .doOnSubscribe(subscription -> {
                            showLoadingDialog("安装中", "安装中,请耐心等待…", false);
                        })
                        .doOnCompleted(this::dismissLoadingDialog)
                        .subscribe(() -> {
                            ToastUtil.toast("安装完成,重新启动游戏");
                            reloadGame();
                        }, throwable -> {
                            ToastUtil.toast("错误：安装DLC或补丁失败");
                            LogUtil.d(TAG, throwable.getMessage());
                        });
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private ProgressDialog progressDialog;

    private void dismissLoadingDialog() {
        if (progressDialog != null)
            progressDialog.dismiss();
    }

    private void showLoadingDialog(String title, String message, boolean cancelable) {
        progressDialog = ProgressDialog.show(EmulationActivity.this, title, message
                , false, cancelable);
    }

    private void onAmiiboSelected(String selectedFile) {
        File file = new File(selectedFile);
        boolean success = false;
        try {
            byte[] bytes = FileUtil.getBytesFromFile(file);
            success = NativeLibrary.LoadAmiibo(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (!success) {
            new AlertDialog.Builder(this)
                    .setTitle(R.string.amiibo_load_error)
                    .setMessage(R.string.amiibo_load_error_message)
                    .setPositiveButton(android.R.string.ok, null)
                    .create()
                    .show();
        }
    }

    public void SelectDLCOrPatchFile() {
        FileBrowserHelper.openFilePicker(this, REQUEST_SELECT_DLC_OR_PATCH,
                R.string.select_dlc_or_patch,
                Arrays.asList("zip", "cia"), false);
    }

    public void ChooseAmiibo() {
        FileBrowserHelper.openFilePicker(this, REQUEST_SELECT_AMIIBO,
                R.string.select_amiibo,
                Collections.singletonList("bin"), false);
    }

    public void RemoveAmiibo() {
        NativeLibrary.RemoveAmiibo();
    }


    @Override
    public boolean dispatchGenericMotionEvent(MotionEvent event) {
        if (inputManager.dispatchGenericMotionEvent(event)) {
            return true;
        }
        return super.dispatchGenericMotionEvent(event);
    }

    public boolean isActivityRecreated() {
        return activityRecreated;
    }

    @Retention(SOURCE)
    @IntDef({MENU_ACTION_EDIT_CONTROLS_PLACEMENT, MENU_ACTION_TOGGLE_CONTROLS, MENU_ACTION_ADJUST_SCALE,
            MENU_ACTION_EXIT, MENU_ACTION_SHOW_FPS, MENU_ACTION_SCREEN_LAYOUT_LANDSCAPE,
            MENU_ACTION_SCREEN_LAYOUT_PORTRAIT, MENU_ACTION_SCREEN_LAYOUT_SINGLE, MENU_ACTION_SCREEN_LAYOUT_SIDEBYSIDE,
            MENU_ACTION_SWAP_SCREENS, MENU_ACTION_RESET_OVERLAY, MENU_ACTION_SHOW_OVERLAY, MENU_ACTION_OPEN_SETTINGS})
    public @interface MenuAction {
    }

    //region修改
    @Override
    public void saveArchive(int id, String filePath, @Nullable String picPath) {
        Completable.fromAction(() -> {
            if (AiwuSimulator.getArchiveCallback() != null) {
                AiwuSimulator.getArchiveCallback().showLoading();
            }
        })
                .observeOn(Schedulers.io())
                .andThen(Completable.fromAction(() -> {
                    if (!TextUtils.isEmpty(picPath)) {
                        archiveSnap(picPath);
                    }
                }))
                .delay(300, TimeUnit.MILLISECONDS)
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(() -> NativeLibrary.SaveState(id),
                        Throwable::printStackTrace);
    }

    @Override
    public void loadArchive(int id, String filePath) {
        NativeLibrary.LoadState(id);
    }

    @Override
    public Context getContext() {
        return this;
    }

    public void showExitConfirmation() {
        NativeLibrary.PauseEmulation();
        TipPop tipPop = DialogUtil.showTip(this, R.string.emulation_close_game_message, v -> {
            mEmulationFragment.stopEmulation();
            finish();
            Process.killProcess(Process.myPid());
        }, null);
        tipPop.setOnDismissListener(dialog -> NativeLibrary.UnPauseEmulation());
    }

    public void updateShowFpsOverlay() {
        mEmulationFragment.updateShowFpsOverlay();
    }

    public void showReloadConfirmation() {
        NativeLibrary.PauseEmulation();
        DialogUtil.showTip(this, R.string.emulation_reload_game_message, v -> {
            reloadGame();
        }, v -> NativeLibrary.UnPauseEmulation(), false);
    }

    public void reloadGame() {
        finish();
        EmulationActivity.launch(EmulationActivity.this, mPath, mSelectedTitle, mMarketRomPath);
    }

    public void hideFloatingLayout() {
        if (mFloatingLayout != null) {
            mFrameContent.removeView(mFloatingLayout);
            mFloatingLayout = null;
        }
    }

    public void refreshFloatingScreenLayout() {
        if (mFloatingLayout != null) {
            mFloatingLayout.displayIvScreenLayout();
        }
    }

    public void setScreenLayoutListener(ScreenLayoutListener mScreenLayoutListener) {
        this.mScreenLayoutListener = mScreenLayoutListener;
    }

    /**
     * 重置屏幕布局到默认
     */
    private void resetScreenLayout() {
        String[] keys = new String[]{SettingsFile.KEY_CUSTOM_LAYOUT,
                SettingsFile.KEY_CUSTOM_TOP_LEFT, SettingsFile.KEY_CUSTOM_TOP_TOP, SettingsFile.KEY_CUSTOM_TOP_RIGHT, SettingsFile.KEY_CUSTOM_TOP_BOTTOM,
                SettingsFile.KEY_CUSTOM_BOTTOM_LEFT, SettingsFile.KEY_CUSTOM_BOTTOM_TOP, SettingsFile.KEY_CUSTOM_BOTTOM_RIGHT, SettingsFile.KEY_CUSTOM_BOTTOM_BOTTOM};
        int[] values = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0};
        Settings mSettings = new Settings();
        mSettings.loadSettings(null);
        for (int i = 0; i < keys.length; i++) {
            String key = keys[i];
            int value = values[i];
            SettingSection rendererSection = mSettings.getSection(Settings.SECTION_LAYOUT);
            Setting customLayout = rendererSection.getSetting(key);
            IntSetting setting = FastSettingDialog.setSelectedValue(value, customLayout, key, Settings.SECTION_LAYOUT);
            if (setting != null) {
                rendererSection.putSetting(setting);
            }
        }
        mSettings.saveSettings(null);
        NativeLibrary.ReloadSettings();
        changeScreenOrientation(EmulationMenuSettings.LayoutOption_MobileLandscape, null);
        PrefsHelper.getInstance().setLastScreenConfigId(EmulationMenuSettings.LayoutOption_MobileLandscape);
    }

    /**
     * 初始化爱吾的部分参数
     */
    public void initAiwuParams() {
        try {
            Settings mSettings = new Settings();
            mSettings.loadSettings(null);
            SettingSection audioSection = mSettings.getSection(Settings.SECTION_AUDIO);
            Setting audioOutput = audioSection.getSetting(SettingsFile.KEY_AUDIO_OUTPUT_ENGINE);
            boolean isEnableSound = FastSettingDialog.isEnableSound(audioOutput);
            AiwuSimulator.setSoundEnable(isEnableSound);

            SettingSection renderSection = mSettings.getSection(Settings.SECTION_RENDERER);
            Setting frameLimitEnabled = renderSection.getSetting(SettingsFile.KEY_FRAME_LIMIT_ENABLED);
            boolean isFrameLimitEnabled = FastSettingDialog.isChecked(frameLimitEnabled);
            if (isFrameLimitEnabled) {
                Setting frameLimit = renderSection.getSetting(SettingsFile.KEY_FRAME_LIMIT);
                int speed = FastSettingDialog.getSelectedValue(frameLimit, 100);
                AiwuSimulator.setSpeedMultiple((int) Math.ceil(speed / 100f));
            } else {
                AiwuSimulator.setSpeedMultiple(1);
            }
            mSettings = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void setSoundEnable(boolean enable) {
        Settings mSettings = new Settings();
        mSettings.loadSettings(null);
        SettingSection audioSection = mSettings.getSection(Settings.SECTION_AUDIO);
        Setting audioOutput = audioSection.getSetting(SettingsFile.KEY_AUDIO_OUTPUT_ENGINE);
        StringSetting setting = FastSettingDialog.enableSound(enable, audioOutput, SettingsFile.KEY_AUDIO_OUTPUT_ENGINE, Settings.SECTION_AUDIO);
        if (setting != null) {
            audioSection.putSetting(setting);
        }
        mSettings.saveSettings(null);
        NativeLibrary.ReloadSettings();
    }

    private void setSpeedUp(int speed) {
        Settings mSettings = new Settings();
        mSettings.loadSettings(null);
        SettingSection renderSection = mSettings.getSection(Settings.SECTION_RENDERER);
        Setting frameLimitEnabled = renderSection.getSetting(SettingsFile.KEY_FRAME_LIMIT_ENABLED);
        Setting frameLimit = renderSection.getSetting(SettingsFile.KEY_FRAME_LIMIT);
        IntSetting enableSetting = FastSettingDialog.setChecked(true, frameLimitEnabled, SettingsFile.KEY_FRAME_LIMIT_ENABLED, Settings.SECTION_RENDERER);
        if (enableSetting != null) {
            renderSection.putSetting(enableSetting);
        }
        IntSetting speedSetting = FastSettingDialog.setSelectedValue(speed * 100, frameLimit, SettingsFile.KEY_FRAME_LIMIT, Settings.SECTION_RENDERER);
        if (speedSetting != null) {
            renderSection.putSetting(speedSetting);
        }
        mSettings.saveSettings(null);
        NativeLibrary.ReloadSettings();
    }

    /**
     * 截图
     */
    private void snap() {
        NativeLibrary.Screenshot((width, height, pixels) -> {
            final Bitmap screenshot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            screenshot.setPixels(pixels, 0, width, 0, 0, width, height);
            Calendar calendar = Calendar.getInstance();
            Date now = calendar.getTime();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd-HHmm", Locale.CHINA);
            String fileName = TextUtils.isEmpty(mSelectedTitle) ? "3ds" : mSelectedTitle + "_" + simpleDateFormat.format(now) + ".png";
            IOUtil.snapAsync(screenshot, fileName);
        });
    }

    private void archiveSnap(@NonNull String picPath) {
        NativeLibrary.Screenshot((width, height, pixels) -> {
            final Bitmap screenshot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            screenshot.setPixels(pixels, 0, width, 0, 0, width, height);
            File file = new File(picPath);
            IOUtil.snap(screenshot, file.getParent(), file.getName());
        });
    }

    public String getPath() {
        return mPath;
    }
    //endregion

}
